function noop () {

}
function bind (fn, ctx) {
  function boundFn (a) {
    const l = arguments.length
    return l 
      ? l > 1
        ? fn.apply(ctx, arguments)
        : fn.call(ctx, a)
      : fn.call(ctx)   

  }
  return boundFn
}
class Vue {
  constructor (options) {
    // 1. 通过属性保存选项的数据
    this.$options = options || {}
    this.$data =  options.data || {}
    this.$el =  typeof options.el === 'string' ? document.querySelector("#app") : ''
    
    if (this.$options.methods) {
      // 存在methods 
      this._initMethods(this, this.$options.methods)
    }
    // 2. 将data中的属性代理到vue 实例上
    this._proxyData(this.$data)
    // 3. 负责调用Observe 数据劫持
    new Observer(this.$data)
  }
  // 将方法挂载到vue 实例 
  _initMethods (vm, methods) {
    for (let key in methods) {
      vm[key] = typeof methods[key] != 'function' ? noop : bind(methods[key], vm)
    }
  }
  _proxyData (data) {
    // 遍历 data 中的所有属性
    Object.keys(data).forEach(key => {
      Object.defineProperty(this, key, {
        // 此处的this 表示的是 vue 实例
        enumerable: true,
        configurable: true,
        get () {
          return data[key]
        },
        set (newVal) {
          if (newVal === data[key]) {
            return 
          }
          data[key] = newVal
          
        }
      })
    })
  }
}